module UART_Send #(
  parameter uart_bps = 115200
)
(
  input clk_50M,
  input rstn,
  input uart_en,
  input [7:0] uart_data,
  output uart_busy,
  output reg uart_tx
);


localparam clk_freq = 50_000_000;
localparam cnt_bps = clk_freq / uart_bps;


// 获取uart_en上升沿
reg [1:0] r_uart_en;
wire pos_uart_en;

always @(posedge clk_50M, negedge rstn) begin
  if(!rstn) begin
    r_uart_en <= 2'd0;
  end
  else begin
    r_uart_en <= {r_uart_en[0], uart_en};
  end
end

assign pos_uart_en = (~r_uart_en[1]) & (r_uart_en[0]);


// 发送状态控制
reg tx_flag;        // 发送标志
reg [7:0] tx_data;  // 待发数据
reg [3:0] tx_cnt;   // 发送数据计数()
reg [15:0] clk_cnt; // 时钟计数

always @(posedge clk_50M, negedge rstn) begin
  if(!rstn) begin
    tx_flag <= 1'd0;
    tx_data <= 8'd0;
  end
  else if(pos_uart_en) begin
    tx_flag <= 1'd1;
    tx_data <= uart_data;
  end
  else if((tx_cnt == 4'd9) &&(clk_cnt == cnt_bps - (cnt_bps/16))) begin
    // 发送结束 停止位提前1/16结束，确保发送时间略小于接收时间
    tx_flag <= 1'd0;
    tx_data <= 8'd0;
  end
  else begin
    tx_flag <= tx_flag;
    tx_data <= tx_data;
  end
end


// 时钟计数，确定数据位
always @(posedge clk_50M, negedge rstn) begin
  if(!rstn) begin
    clk_cnt <= 16'd0;
  end
  else if(tx_flag) begin
    if(clk_cnt < cnt_bps - 1) begin
      clk_cnt <= clk_cnt + 16'd1;
    end
    else begin
      clk_cnt <= 16'd0;
    end
  end
  else begin
    clk_cnt <= 16'd0;
  end
end


// 发送数据计数
always @(posedge clk_50M, negedge rstn) begin
  if(!rstn) begin
    tx_cnt <= 4'd0;
  end
  else if(tx_flag) begin
    if(clk_cnt == cnt_bps - 1) begin
      tx_cnt <= tx_cnt + 4'd1;
    end
    else begin
      tx_cnt <= tx_cnt;
    end
  end
  else begin
    tx_cnt <= 4'd0;
  end
end


// 根据tx_cnt发送数据
always @(posedge clk_50M, negedge rstn) begin
  if(!rstn) begin
    uart_tx <= 1'd1;
  end
  else if(tx_flag) begin
    case(tx_cnt)
      4'd0 : uart_tx <= 1'b0; // 起始位
      4'd1 : uart_tx <= tx_data[0]; // LSB
      4'd2 : uart_tx <= tx_data[1];
      4'd3 : uart_tx <= tx_data[2];
      4'd4 : uart_tx <= tx_data[3];
      4'd5 : uart_tx <= tx_data[4];
      4'd6 : uart_tx <= tx_data[5];
      4'd7 : uart_tx <= tx_data[6];
      4'd8 : uart_tx <= tx_data[7];
      4'd9 : uart_tx <= 1'b1; // 停止位
      default : ;
    endcase
  end
  else begin
    uart_tx <= 1'd1;
  end
end


assign uart_busy = tx_flag;


endmodule